<?php

declare(strict_types=1);

namespace App\Services\Admin;

use App\Exception\InvalidRequestException;
use App\Utils\Services\BaseServices;
use App\Model\Admin\Menu as MenuModel;
use Donjan\Casbin\Enforcer;
use Hyperf\Database\Model\Relations\HasMany;
use function Hyperf\Translation\__;

/**
 * Class Menu
 * @package App\Services\Admin
 */
Class Menu extends BaseServices
{
    public function __construct(
        protected Permission $permissionServices
    )
    {
        parent::__construct();
    }

    public function model():string
    {
        return MenuModel::class;
    }

    /**
     * 获取应用用户的菜单树
     * @param array $info
     * @param string $app
     * @return \App\Model\Model[]|\Hyperf\Database\Model\Collection|mixed
     */
    public function getTree(array $info, string $app='admin')
    {
        $map = [];
        $secondMenuIds = [];
        $menuIds = [];
        if (!$info['is_admin']) {
            $roles = Enforcer::getRolesForUserInDomain((string)$info['id'], $app);
            if (!$roles) {
                throw new InvalidRequestException(__('message.binding', ['name' => __('model.table.role')]));
            }
            $permissions = [];
            foreach ($roles as $role) {
                $permissionEnforce = Enforcer::getPermissionsForUserInDomain((string)$role, $app);
                foreach ($permissionEnforce as $item) {
                    array_push($permissions, "{$item[2]}|{$item[3]}");
                }
            }
            $menuIds = $this->permissionServices
                ->whereRaw('concat_ws("|", path, method) in (?)', [implode(',', $permissions)])
                ->groupBy('menu_id')
                ->pluck('menu_id')
                ->toArray(); // 查询最后一级目录
            $secondMenuIds = $this->whereIn('id', $menuIds)->groupBy('parent_id')->pluck('parent_id'); // 查询第二级目录
            $firstMenuIds = $this->whereIn('id', $secondMenuIds)->groupBy('parent_id')->pluck('parent_id'); // 查询一级目录
            $map[] = [function($query)use($firstMenuIds){
                $query->whereIn('id', $firstMenuIds);
            }];
        }
        $map[] = ['app', '=', $app];
        $map[] = ['parent_id', '=', 0];
        $map[] = ['status', '=', 1];
        $menu = $this->with(['children'=>function(HasMany $hasMany)use($info, $secondMenuIds, $menuIds){
            $map = [];
            if (!$info['is_admin']) {
                $map[] = [function($query)use($secondMenuIds){
                    $query->whereIn('id', $secondMenuIds);
                }];
            }
            $map[] = ['status', '=', 1];
            $hasMany->with(['children'=>function(HasMany $hasMany)use($info, $menuIds){
                $map = [];
                if (!$info['is_admin']) {
                    $map[] = [function($query)use($menuIds){
                        $query->whereIn('id', $menuIds);
                    }];
                }
                $map[] = ['status', '=', 1];
                $hasMany->with(['permission'=>function(HasMany $hasMany){
                    $hasMany->select(['id', 'menu_id', 'link', 'path', 'method'])->where('status', 1);
                }])
                    ->where($map)
                    ->orderBy('sort');
            }])
                ->where($map)
                ->orderBy('sort');
        }])
            ->where($map)
            ->orderBy('sort')
            ->get();

        return $menu;
    }
}
